package com.weibei.common.redis.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import org.springframework.util.StringUtils;

/**
 * Redis工具类
 */
@Component
public class RedisUtils
{
    private static final Logger logger = LoggerFactory.getLogger(RedisUtils.class);

    @Autowired
    private RedisTemplate<String, Object>   redisTemplate;

    @Resource(name = "stringRedisTemplate")
    private ValueOperations<String, String> valueOperations;

    @Resource(name = "stringRedisTemplate")
    private SetOperations<String, Object> setOps;

    /**  默认过期时长，单位：秒 */
    public final static long                DEFAULT_EXPIRE = 60 * 60 * 24;

    /**  不设置过期时长 */
    public final static long                NOT_EXPIRE     = -1;

    /**
     * 插入缓存默认时间
     * @param key 键
     * @param value 值
     * @author zmr
     */
    public void set(String key, Object value)
    {
        set(key, value, DEFAULT_EXPIRE);
    }

    /**
     * 插入缓存
     * @param key 键
     * @param value 值
     * @param expire 过期时间(s)
     * @author zmr
     */
    public void set(String key, Object value, long expire)
    {
        valueOperations.set(key, value.toString());
        redisTemplate.expire(key, expire, TimeUnit.SECONDS);
    }

    /**
     * 返回字符串结果
     * @param key 键
     * @return
     * @author zmr
     */
    public String get(String key)
    {
        return valueOperations.get(key);
    }

    /**
     * 返回指定类型结果
     * @param key 键
     * @param clazz 类型class
     * @return
     * @author zmr
     */
    public <T> T get(String key, Class<T> clazz)
    {
        String value = valueOperations.get(key);
        return value == null ? null : fromJson(value, clazz);
    }

    /**
     * 删除缓存
     * @param key 键
     * @author zmr
     */
    public void delete(String key)
    {
        redisTemplate.delete(key);
    }

    /**
     * Object转成JSON数据
     */
    private String toJson(Object object)
    {
        if (object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double
                || object instanceof Boolean || object instanceof String)
        {
            return String.valueOf(object);
        }
        return JSON.toJSONString(object);
    }

    /**
     * JSON数据，转成Object
     */
    private <T> T fromJson(String json, Class<T> clazz)
    {
        return JSON.parseObject(json, clazz);
    }

    /**
     * 对某个键的值自增并获取自增值，当传入的key不存在时，会自动创建一个key，默认值为0,
     * 当key存在时，会将存在的值+1后返回
     * @param key 键
     * @param cacheSeconds 超时时间，0为不超时
     * @param value 键的初始值设定
     * @return
     */
    public long incr(String key, long cacheSeconds,Object value) {
        try {
            RedisAtomicLong entityIdCounter;
            String keyValue = this.get(key);
            if(value == null || value == "" || !StringUtils.isEmpty(keyValue)){
                entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
            }else{
                entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory(),Long.valueOf(value.toString()));
            }
            Long increment = entityIdCounter.incrementAndGet();
            if (increment > 0  && cacheSeconds > 0) {//初始设置过期时间
                entityIdCounter.expire(cacheSeconds, TimeUnit.SECONDS);//单位秒
            }
            return increment;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }


    /**
     * 列表添加(尾部添加)
     * @param k
     * @param v
     */
    public void lRightPush(String k,Object v){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.rightPush(k,v);
    }

    public void leftPush(String k,Object v){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        list.leftPush(k,v);
    }

    /**
     * 列表获取
     * @param k
     * @param l
     * @param l1
     * @return
     */
    public List<Object> lRange(String k, long l, long l1){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        return list.range(k,l,l1);
    }

    /**
     * 移出并获取列表的第一个元素，当列表不存在或者为空时，返回Null
     * @param key
     * @return
     */
    public Object lpop(String key){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        Object value = "";
        try {
            value = list.leftPop(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;
    }

    public Object rpop(String key){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        Object value = "";
        try {
            value = list.rightPop(key);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 移出并获取列表的第一个元素，当列表不存在或者为空时，返回Null
     * @param key
     * @return
     */
    public Object blpop(String key,Long timeout){
        ListOperations<String, Object> list = redisTemplate.opsForList();
        Object value = "";
        try {
            value = list.leftPop(key,timeout,TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 添加元素
     * @param key
     * @param member
     * @return
     */
    public long sadd(String key, Object member){
        return setOps.add(key, member);
    }

    /**
     * 移除元素
     * @param key
     * @param member
     * @return
     */
    public long sRemove(String key, Object member){
        return setOps.remove(key, member);
    }

    /**
     * 判断 member 元素是否是集合 key 的成员
     * @param key
     * @param member
     * @return
     */
    public Boolean isMember(String key, Object member){
        return setOps.isMember(key, member);
    }

    /**
     * 返回集合中的所有成员
     * @param key
     * @return
     */
    public Set<Object> sMembers(String key){
        return setOps.members(key);
    }

    /**
     * 遍历set 返回list
     * @param key
     * @return
     */
    public List<Object> scanToList(String key){
        List<Object> list = new ArrayList<>();
        Cursor<Object> curosr = setOps.scan(key, ScanOptions.NONE);
        while(curosr.hasNext()){
            list.add(curosr.next());
        }
        return list;
    }

    /**
     * 对某个键的值自增并获取自增值
     * @param key 键
     * @param cacheSeconds 超时时间，0为不超时
     * @return
     */
    public long incrementAndGet(String key, long cacheSeconds) {
        try {
            RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
            Long increment = entityIdCounter.incrementAndGet();
            if (increment > 0  && cacheSeconds > 0) {//初始设置过期时间
                entityIdCounter.expire(cacheSeconds, TimeUnit.SECONDS);//单位秒
            }
            return increment;
        } catch (Exception e) {
            logger.warn("set "+ key ,e);
        }
        return 0;
    }

    /**
     * 对某个键的值自减并获取自减值
     * @param key 键
     * @param cacheSeconds 超时时间，0为不超时
     * @return
     */
    public long decrementAndGet(String key, long cacheSeconds) {
        try {
            RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
            Long decrement = entityIdCounter.decrementAndGet();
            if (decrement > 0  && cacheSeconds > 0) {//初始设置过期时间
                entityIdCounter.expire(cacheSeconds, TimeUnit.SECONDS);//单位秒
            }
            return decrement;
        } catch (Exception e) {
            logger.warn("set "+ key ,e);
        }
        return 0;
    }

    /**
     * @Author zhangchi
     * @Description //判断是否有key
     * @Date 15:35 2021/1/11
     * @Param [key]
     * @return boolean
     **/
    public boolean exists(final String key) {
        return redisTemplate.hasKey(key);
    }

}
